Shortest Job Remaining First (SJR) Scheduling Algorithm
Introductionā
The Shortest Job Remaining First (SJR) scheduling algorithm is a preemptive scheduling technique used in operating systems. It selects the process with the smallest remaining burst time to execute next, allowing for efficient handling of processes with varying execution times.
Exampleā
Consider four processes with the following arrival and burst times:
- Process 1: Arrival time
1
, Burst time3
- Process 2: Arrival time
2
, Burst time3
- Process 3: Arrival time
3
, Burst time5
- Process 4: Arrival time
4
, Burst time1
Using the SJR algorithm, the processes will be executed based on their remaining times and arrival sequence.
Problem Definitionā
Given a list of processes with their corresponding arrival times and burst times, calculate the waiting times, turnaround times, average waiting time, and average turnaround time for the processes.
Key Conceptsā
- Waiting Time: The amount of time a process spends waiting before it starts executing.
- Turnaround Time: The total time taken for a process from arrival to completion, which includes both the waiting time and burst time.
SJR Scheduling Approachā
In the SJR algorithm:
- The waiting time is calculated based on the execution order of the processes with the shortest remaining time.
- Processes can be preempted if a newly arriving process has a shorter burst time than the remaining time of the currently executing process.
Code Implementation in Pythonā
Below is the Python implementation for the SJR scheduling algorithm:
from __future__ import annotations
import pandas as pd
def calculate_waiting_time(arrival_time: list[int], burst_time: list[int], num_processes: int) -> list[int]:
remaining_time = burst_time.copy()
waiting_time = [0] * num_processes
completed_processes = 0
current_time = 0
min_remaining_time = float('inf')
shortest_process = 0
process_found = False
while completed_processes != num_processes:
for j in range(num_processes):
if (arrival_time[j] <= current_time and remaining_time[j] > 0
and remaining_time[j] < min_remaining_time):
min_remaining_time = remaining_time[j]
shortest_process = j
process_found = True
if not process_found:
current_time += 1
continue
remaining_time[shortest_process] -= 1
min_remaining_time = remaining_time[shortest_process]
if min_remaining_time == 0:
min_remaining_time = float('inf')
if remaining_time[shortest_process] == 0:
completed_processes += 1
finish_time = current_time + 1
waiting_time[shortest_process] = finish_time - arrival_time[shortest_process] - burst_time[shortest_process]
waiting_time[shortest_process] = max(waiting_time[shortest_process], 0)
current_time += 1
return waiting_time
def calculate_turnaround_time(burst_time: list[int], num_processes: int, waiting_time: list[int]) -> list[int]:
return [burst + wait for burst, wait in zip(burst_time, waiting_time)]
def calculate_average_times(waiting_time: list[int], turnaround_time: list[int], num_processes: int) -> None:
total_waiting_time = sum(waiting_time)
total_turnaround_time = sum(turnaround_time)
print(f"Average waiting time = {total_waiting_time / num_processes:.5f}")
print("Average turnaround time =", total_turnaround_time / num_processes)
if __name__ == "__main__":
print("Enter how many processes you want to analyze:")
num_processes = int(input())
burst_time = [0] * num_processes
arrival_time = [0] * num_processes
processes = list(range(1, num_processes + 1))
for i in range(num_processes):
print("Enter the arrival time and burst time for process:", i + 1)
arrival_time[i], burst_time[i] = map(int, input().split())
waiting_time = calculate_waiting_time(arrival_time, burst_time, num_processes)
turnaround_time = calculate_turnaround_time(burst_time, num_processes, waiting_time)
calculate_average_times(waiting_time, turnaround_time, num_processes)
fcfs = pd.DataFrame(
list(zip(processes, burst_time, arrival_time, waiting_time, turnaround_time)),
columns=[
"Process",
"Burst Time",
"Arrival Time",
"Waiting Time",
"Turnaround Time",
],
)
pd.set_option("display.max_rows", fcfs.shape[0] + 1)
print(fcfs)
Explanation of the Code
Waiting Time Calculationā
The waiting time is calculated by tracking the remaining times of each process as they are executed in order of their shortest remaining time.
Turnaround Time Calculationā
Turnaround time is calculated as the sum of waiting time and burst time for each process.
Average Timesā
The average waiting time and turnaround time are printed by dividing the total by the number of processes.
Example Outputā
For the input where the arrival and burst times are:
- Arrival Time:
[1, 2, 3, 4]
- Burst Time:
[3, 3, 5, 1]
The output will display the waiting and turnaround times, as well as the average values for all processes.
Time and Space Complexityā
- Time Complexity: The time complexity is O(nĀ²) due to the nested loops for finding the shortest job remaining.
- Space Complexity: The space complexity is O(n) for storing waiting times and turnaround times.
Conclusionā
The Shortest Job Remaining First (SJR) scheduling algorithm effectively minimizes waiting times for processes by executing the shortest jobs first. However, it may lead to starvation for longer processes if shorter jobs continue to arrive.